<template>
	<view class="chat-interface">
		<view class="scroll-view">
			<image v-if="messageList.loading" class="history-loaded" src="/static/images/loading.svg" />
			<view v-else :class="messageList.allLoaded ? 'history-loaded' : 'load'" @click="loadHistoryMessage(false)">
				<view>{{ messageList.allLoaded ? '已经没有更多的历史消息' : '下拉获取历史消息' }}</view>
			</view>
			<view v-for="(message, index) in messageList.messages" :key="index">
				<view class="time-lag">
					{{ renderMessageDate(message, index) }}
				</view>
				<view class="message-item" :key="message.clientMsgID" v-if="message.contentType == '101'"
					:class="{ 'self': message.sendID === currentUser.userID }">
					<image class="avatar"
						:src="message.sendID === currentUser.userID ? currentUser.avatar : message.senderFaceUrl">
					</image>
					<view v-if="message.contentType == '101'" class="content-text"
						v-html="renderTextMessage(message.textElem.content)" @longpress="showActionPopup(message)">
					</view>
				</view>
				<view v-if="message.contentType == '110'" class="content-game" @longpress="showActionPopup(message)">
					<view class="game_name">{{ JSON.parse(message.customElem.extension).game_name }} ></view>
					<view class="game_info">
						<view>{{ JSON.parse(message.customElem.extension).starttime }}</view>
						<view>{{ JSON.parse(message.customElem.extension).court_name }}</view>
						<view>
							招募时间截止至{{ JSON.parse(message.customElem.extension).apply_deadline_time }}
						</view>
					</view>
				</view>
			</view>
		</view>
		<view class="action_box">
			<view class="action_keyinput">
				<input type="text" v-model="text" placeholder="请输入消息" class="text_input" />
				<view @click="switchEmojiKeyboard">
					<image class="more" v-if="emoji.visible" src="/static/images/jianpan.png"></image>
					<image class="more" v-else src="/static/images/emoji.png"></image>
				</view>
				<button @click="sendGameMessage">发球局</button>
				<button @click="sendMessage" v-if="text.length > 0">发送</button>
			</view>
			<view class="action_emoji" v-if="emoji.visible">
				<image class="emoji_item" v-for="(emojiItem, emojiKey, index) in emoji.map" :key="index"
					:src="emoji.url + emojiItem" @click="chooseEmoji(emojiKey)"></image>
			</view>
		</view>
		<view class="action-popup" @touchmove.stop.prevent v-if="actionPopup.visible">
			<view class="layer"></view>
			<view class="action-list">
				<view class="action-item" @click="deleteSingleMessage">删除</view>
				<view class="action-item" v-if="actionPopup.recallable" @click="recallMessage">撤回</view>
				<view class="action-item" @click="hideActionPopup">取消</view>
			</view>
		</view>
	</view>
</template>

<script setup>
import EmojiDecoder from '../../lib/EmojiDecoder.js';
import dayjs from 'dayjs';
import { computed, reactive, ref, unref, nextTick, onMounted, onUnmounted } from 'vue';
import { onLoad, onReady, onShow, onPullDownRefresh, onUnload } from '@dcloudio/uni-app';

const emojiUrl = 'https://imgcache.qq.com/open/qcloud/tim/assets/emoji/';
const emojiMap = {
	'[么么哒]': 'emoji_3@2x.png',
	'[乒乓]': 'emoji_4@2x.png',
	'[便便]': 'emoji_5@2x.png',
	'[信封]': 'emoji_6@2x.png',
	'[偷笑]': 'emoji_7@2x.png',
	'[傲慢]': 'emoji_8@2x.png'
};
const emoji = reactive({
	url: emojiUrl,
	map: emojiMap,
	visible: false,
	decoder: new EmojiDecoder(emojiUrl, emojiMap),
})

const actionPopup = reactive({
	visible: false,
	message: null,
	recallable: false,
})

const messageSelector = reactive({
	visible: false,
	message: null
})

const text = ref('')
const friend = ref(null)
const to = ref(null)
const currentUser = {
	userID: '1101',
	avatar: 'https://tennis.yakexi.tech/uploads/20250319/5fdad0c4e0063fd48d02f0acb1029783.jpeg'
}

const messageList = reactive({
	messages: reactive([]),
	allLoaded: false,
	loading: false
})

const conversationID = ref(null)
const startClientMsgID = ref('')
const lastMinSeq = ref(0);

onLoad((options) => {
	conversationID.value = options.conversationID
	let attempts = 0;
	const initChatList = async () => {
		const { data: loginStatus } = await uni.$openIM.getLoginStatus();
		if (3 == loginStatus) {
			loadHistoryMessage(true)
		} else {
			attempts++;
			if (attempts < 3) {
				setTimeout(initChatList, 2000);
			} else {
				console.log('无法得到对话list');
			}
		}
	};

	initChatList();
})

onMounted(() => {
	uni.$emitter.on('OnRecvNewMessages', (data) => {
		let newMessages = data.data;
		console.log('private page 收到新消息事件', newMessages)
		messageList.messages = messageList.messages.concat(newMessages);
		// //聊天时，收到消息标记为已读
		markPrivateMessageAsRead();
		// //收到新消息，是滚动到最底部
		scrollToBottom();
	})
	uni.$emitter.on('OnNewRecvMessageRevoked', (data) => {
		console.log('private page 收到撤回消息事件', data)
		messageList.messages = messageList.messages.filter(message => message.clientMsgID !== data.data.clientMsgID)
	})
	uni.$emitter.on('onConversationChanged', (data) => {
		console.log('private page 收到删除消息事件', data)
		messageList.messages = messageList.messages.filter(message => message.clientMsgID !== data.data.clientMsgID)
	})
})

onUnmounted(() => {
	uni.$emitter.off('OnRecvNewMessages');
	uni.$emitter.off('OnNewRecvMessageRevoked');
})


function showActionPopup(message) {
	const MAX_RECALLABLE_TIME = 3 * 60 * 1000; //3分钟以内的消息才可以撤回
	messageSelector.message = message;
	if ((Date.now() - message.sendTime) < MAX_RECALLABLE_TIME && message.sendID === currentUser.userID && message.status == 2) {
		actionPopup.recallable = true;
	} else {
		actionPopup.recallable = false;
	}
	actionPopup.visible = true;
}

function hideActionPopup() {
	actionPopup.visible = false;
	actionPopup.message = null;
}

function deleteSingleMessage() {
	uni.showModal({
		content: '确认删除？',
		success: (res) => {
			actionPopup.visible = false;
			if (res.confirm) {
				deleteMessage();
			}
		},
	})
}

function deleteMessage() {
	uni.$openIM.deleteMessage({
		conversationID: conversationID.value,
		clientMsgID: messageSelector.message.clientMsgID,
	}).then(({ data }) => {
		let index = messageList.messages.indexOf(messageSelector.message);
		if (index > -1) {
			messageList.messages.splice(index, 1);
		}
		messageSelector.message = null;
	}).catch(({ errCode, errMsg }) => {
		// 调用失败
		console.log('删除消息失败', errCode, errMsg);
	});
}

async function recallMessage() {
	actionPopup.visible = false;
	try {
		const { data } = await uni.$openIM.revokeMessage({
			conversationID: conversationID.value,
			clientMsgID: messageSelector.message.clientMsgID,
		});
		console.log('撤回成功', data);
	} catch ({ errCode, errMsg }) {
		// 调用失败
		console.log('撤回失败', errCode, errMsg);
	}
}

onPullDownRefresh((e) => {
	loadHistoryMessage(false);
})

function chooseEmoji(emojiKey) {
	console.log('emojiKey', emojiKey)
	text.value += emojiKey;
}

function switchEmojiKeyboard() {
	emoji.visible = !emoji.visible;
}

async function loadHistoryMessage(whetherScrollToBottom) { //历史消息
	messageList.loading = true;
	let lastMessageTimeStamp = null;
	let lastMessage = messageList.messages[0];
	if (lastMessage) {
		lastMessageTimeStamp = lastMessage.timestamp;
	}

	try {
		const { data } = await uni.$openIM.getAdvancedHistoryMessageList({
			conversationID: conversationID.value,
			startClientMsgID: startClientMsgID.value,
			count: 20,
			lastMinSeq: lastMinSeq.value,
		});
		console.log('获取会话成功', data);


		uni.stopPullDownRefresh();
		messageList.loading = false;
		messageList.allLoaded = data.isEnd;
		let messages = data.messageList.filter(message => message.contentType !== 2101); //过滤掉撤回消息
		messageList.messages = [...messages, ...messageList.messages];

		startClientMsgID.value = data.messageList[data.messageList.length - 1].clientMsgID
		lastMinSeq.value = data.lastMinSeq

		if (whetherScrollToBottom) {
			scrollToBottom();
			//收到的消息设置为已读
			markPrivateMessageAsRead();
		}
	} catch ({ errCode, errMsg }) {
		console.log('获取会话失败', errCode, errMsg);
		uni.stopPullDownRefresh();
		messageList.loading = false;
	}
}

function renderMessageDate(message, index) {
	if (index === 0) {
		return humanFormatTime(message.sendTime)
	} else {
		if (message.sendTime - messageList.messages[index - 1].sendTime > 5 * 60 * 1000) {
			return humanFormatTime(message.sendTime)
		}
	}
	return '';
}

function renderTextMessage(message) {
	return '<span>' + emoji.decoder.decode(message) + '</span>'
}

function sendMessage() {
	uni.$openIM.createTextMessage(text.value).then(({ data }) => {
		console.log('创建消息成功', data);
		uni.$openIM.sendMessage({
			recvID: '1100',
			message: data
		}).then(({ data }) => {
			console.log('Message sent successfully', data);
			messageList.messages.push(data);
			scrollToBottom();
			text.value = '';
		}).catch(({ errCode, errMsg }) => {
			console.log('Failed to send message', errCode, errMsg);
		});
	}).catch(({ errCode, errMsg }) => {
		console.log('Failed to send message', errCode, errMsg);
	});
}

function sendGameMessage() {
	uni.$openIM.createCustomMessage({
		data: '这是测试的球局消息',
		extension: JSON.stringify({
			id: 13,
			game_name: '这是测试的球局名',
			starttime: '2025-02-04 02:00:00',
			court_name: '怡然网球公园',
			apply_deadline_time: '2025-02-03 03:02:00',
		}),
	}).then(({ data }) => {
		console.log('创建球局消息成功', data)
		uni.$openIM.sendMessage({
			recvID: '1100',
			message: data
		}).then(({ data }) => {
			console.log('球局消息发送成功', data);
			messageList.messages.push(data);
			scrollToBottom();
		}).catch(({ errCode, errMsg }) => {
			console.log('球局消息发送失败', errCode, errMsg);
		});
	}).catch(({ errCode, errMsg }) => {
		// 调用失败
		console.log('创建球局消息失败', errCode, errMsg)
	});
}

async function markPrivateMessageAsRead() {
	try {
		const { data } = await uni.$openIM.markConversationMessageAsRead(conversationID.value);
		console.log('标记私聊已读成功', data);
	} catch ({ errCode, errMsg }) {
		console.log('标记私聊已读失败', errCode, errMsg);
	}
}

function scrollToBottom() {
	console.log('scrollToBottom')
	nextTick(() => {
		uni.pageScrollTo({
			scrollTop: 2000000,
			duration: 0
		});
	});
}

function humanFormatTime(timestamp) {
	const today = dayjs().startOf('day');
	const date = dayjs(timestamp);

	if (date.isSame(today, 'day')) {
		// 如果是今天
		return `今天 ${date.format('HH:mm')}`;
	} else if (date.isSame(today.subtract(1, 'day'), 'day')) {
		// 如果是昨天
		return `昨天 ${date.format('HH:mm')}`;
	} else {
		// 如果是前天或更早
		return date.format('MM/DD HH:mm');
	}
}

</script>

<style scoped lang="scss">
.chat-interface {
	height: 100%;
	background-color: #F1F1F1;

	.scroll-view {
		padding: 10rpx;
		padding-bottom: 168rpx;
		-webkit-overflow-scrolling: touch;
		background-color: #F1F1F1;

		.history-loaded {
			font-size: 34rpx;
			height: 60rpx;
			line-height: 60rpx;
			width: 100%;
			text-align: center;
			color: #cccccc;
		}

		.load {
			font-size: 34rpx;
			height: 60rpx;
			line-height: 60rpx;
			width: 100%;
			text-align: center;
			color: #d02129;
		}

		.time-lag {
			font-size: 34rpx;
			text-align: center;
		}

		.message-recalled {
			display: flex;
			align-items: center;
			justify-content: center;
			line-height: 56rpx;
			font-size: 34rpx;
			text-align: center;
			color: grey;

			.message-recalled-self {
				display: flex;

				span {
					margin-left: 10rpx;
					color: #d02129;
				}
			}
		}

		.message-item {
			flex: 1;
			overflow: hidden;
			display: flex;
			margin-top: 10rpx;
		}

		.message-item.self {
			overflow: hidden;
			display: flex;
			justify-content: flex-start;
			flex-direction: row-reverse;
		}

		.avatar {
			width: 84rpx;
			height: 84rpx;
			border-radius: 50%;
		}

		.content-text {
			font-size: 34rpx;
			line-height: 44rpx;
			margin: 0 20rpx;
			max-width: 520rpx;
		}

		.content-game {
			margin: 20rpx;
			padding: 20rpx;
			background-color: #cccccc;

			.invite-text {
				font-size: 24rpx;
				line-height: 44rpx;
				text-align: center;
			}

			.game-box {
				display: flex;
				flex-direction: column;
				justify-content: flex-start;
				align-items: flex-start;
			}
		}

	}

	.action_box {
		position: fixed;
		bottom: 0;
		left: 0;
		width: 100%;
		background-color: #f8f8f8;
		padding: 10px;

		.action_keyinput {
			display: flex;
			flex-direction: row;
			justify-content: space-between;
			align-items: center;

			.text_input {
				flex: 1;
				border: 1px solid #ccc;
				border-radius: 10rpx;
				padding: 10rpx;
			}

			image {
				width: 60rpx;
				height: 60rpx;
			}
		}

		.action_emoji {
			height: 200rpx;
			overflow-y: auto;
			padding: 20rpx;
			display: flex;
			flex-direction: row;
			flex-wrap: wrap;
			justify-content: flex-start;
			gap: 24rpx;
			align-items: flex-start;

			.emoji_item {
				width: 60rpx;
				height: 60rpx;
			}
		}



		.my-game-panel {
			height: 900rpx;
			overflow-y: auto;
			padding: 20rpx;

			.title {
				font-size: 34rpx;
				font-weight: bold;
				text-align: center;
			}

			.game-list {
				width: 100%;

				display: flex;
				flex-direction: column;
				justify-content: flex-start;

				.item {
					.game_name {
						margin-left: 10rpx;
					}

					.participant_wrapper {
						display: flex;
						flex-direction: row;
						justify-content: space-between;
						align-items: center;

						.avatar_image {
							width: 56rpx;
							height: 56rpx;
							border-radius: 50%;
						}

						.button_wrapper {
							display: flex;
							flex-direction: row;
							justify-content: space-between;
							align-items: center;
						}
					}
				}
			}

			.no-game {
				height: 100%;
				display: flex;
				flex-direction: column;
				justify-content: center;
				align-items: center;
			}
		}
	}

	.action-popup {
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		display: flex;
		justify-content: center;
		align-items: center;

		.layer {
			position: fixed;
			top: 0;
			left: 0;
			right: 0;
			bottom: 0;
			background: rgba(51, 51, 51, 0.5);
			z-index: 999;
		}

		.action-list {
			width: 350rpx;
			background: #434343;
			position: relative;
			z-index: 1000;
			border-radius: 20rpx;
			overflow: hidden;
		}

		.action-item {
			text-align: center;
			height: 100rpx;
			line-height: 100rpx;
			font-size: 34rpx;
			color: #ffffff;
			border-bottom: 1px solid #EFEFEF;

			&:last-child {
				border: none;
			}
		}
	}
}
</style>
